# encoding = utf-8

'''
Author: Du
Blog：https://www.cnblogs.com/Du704/
 
Date: 2020/4/6 17:06
'''
from sqlalchemy.dialects.sqlite import INTEGER, VARCHAR, DATETIME, CHAR, BOOLEAN
from sqlalchemy import Column, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import re, glob, datetime, os
from img_tools import new_img_url
from concurrent.futures import ThreadPoolExecutor

Base = declarative_base()
base_path = './source/_posts/'


class Blog(Base):
    '''
    sqlalchemy生成的博客表
    '''
    __tablename__ = 'blog'

    id = Column(INTEGER, primary_key=True, autoincrement=True)
    file_name = Column(VARCHAR(60), index=True)
    title = Column(VARCHAR(60), nullable=True)
    date = Column(CHAR(20), default=datetime.datetime.now)
    categories = Column(VARCHAR(60), nullable=True)
    tags = Column(VARCHAR(60), nullable=True)
    toc = Column(BOOLEAN, default=True)

    replace_img = Column(BOOLEAN, default=False)
    sync = Column(BOOLEAN, default=True)

    def __str__(self):
        return self.file_name

    def __repr__(self):
        return self.file_name


engine = create_engine(
    'sqlite:///h_blog.db', encoding='utf8'
    # max_overflow=0,  # 超过连接池大小外最多创建的连接， sqlite不支持
    # pool_size=5,  # 连接池大小
    # pool_timeout=30,  # 池中没有线程最多等待的时间，否则报错
    # pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收（重置）
)
Connection = sessionmaker(bind=engine)


def db_create():
    Base.metadata.create_all(engine)


def db_drop():
    Base.metadata.drop_all(engine)


def db_init(*args, **kwargs):
    com = input("您确认要初始化数据库吗（Y/N），确认之前请先保存数据哦！")
    if com.strip() in ('y', 'Y'):
        try:
            db_drop()
        except Exception:
            ...
        db_create()
        print("数据库初始化完成！")
    else:
        print("初始化已取消。")


def get_all_blog(conn):
    query = conn.query(Blog).all()
    return query


def add_update_blog(conn, blog):
    if isinstance(blog, dict):
        obj = conn.query(Blog).filter(Blog.file_name == blog.get('file_name'))
        if not obj.first():
            conn.add(Blog(**blog))
            print("add success!")
        else:
            obj.update(blog)
            print("update success!")
    else:
        try:
            for i in blog:
                add_update_blog(conn, i)
        except Exception as e:
            print('这条数据有误哦！ %s' % blog)

    conn.commit()


def get_all_md(base_path=base_path):
    blog_list = list()
    for md_path in glob.glob(base_path + '*.md'):
        # print(md_path)
        file_name = os.path.basename(md_path)
        file_name, _ = os.path.splitext(file_name)
        end, blog_dic, _ = get_md_msg(md_path)
        blog_dic['file_name'] = file_name
        if end == -1:
            ...
        else:
            if blog_dic.get('toc'):
                blog_dic['toc'] = True if blog_dic.get('toc') == 'true' else False

        blog_list.append(blog_dic)

    return blog_list


def add_all_md_to_db(conn, base_path=base_path):
    print(f'正在扫描 {base_path} 下的所有 md 文件。。。')
    blog_list = get_all_md(base_path)
    add_update_blog(conn, blog_list)
    print(f"共追加/更新 {len(blog_list)} 条数据！")


def modify_md(conn, blog_obj, base_path=base_path):
    file_name = blog_obj.file_name
    yml_dict = {
        'title': blog_obj.title,
        'date': blog_obj.date,
        'categories': blog_obj.categories,
        'tags': blog_obj.tags,
        'toc': blog_obj.toc,
    }

    end, blog_dic, content = get_md_msg(base_path + file_name + '.md')

    yml = '---\n'
    for k, v in yml_dict.items():
        if v is None or len(str(v)) == 0:
            continue
        if k == 'date':
            v = str(v)[:19]
        elif k == 'toc':
            v = 'true' if v else 'false'
        yml += str(k) + ': ' + str(v) + '\n'
    yml += '---'
    end = end if end > 0 else -3
    content = yml + content[end + 3:]

    with open(base_path + file_name + '.md', 'w', encoding='utf8') as f:
        f.write(content)

    conn.query(Blog).filter(Blog.id == blog_obj.id).update({'sync': True})
    conn.commit()
    print('modify success!')
    return yml_dict


def get_md_msg(md_path):
    with open(md_path, 'r', encoding='utf8') as f:
        data = f.read()
    yml = ''
    end = -1

    if data.startswith('---\n'):
        end = data.find('---', 1)
        yml = data[3:end] if end > 0 else yml

    # print(re.findall(':(.*?)\n',yml))
    yml_dic = {v[0]: v[1].strip() for v in re.findall('(.*?):(.*?)\n', yml)}
    return end, yml_dic, data


def sync_data_from_db(conn):
    blogs = conn.query(Blog).filter(Blog.sync == False).all()
    for b in blogs:
        modify_md(conn, b)
    print(f"共同步 {len(blogs)} 条数据！")


def replace_img(conn, blog_obj, base_path=base_path):
    file_name = blog_obj.file_name
    with open(base_path + file_name + '.md', 'r', encoding='utf8') as f:
        content = f.read()

    img_url = re.findall('!\[]\((.*?)\)', content)
    error = 0
    print(f"正在替换 {file_name} 的图片。。。")
    for i in img_url:
        if not i.startswith('http://pic.yupoo.com'):
            data, msg = new_img_url(i)
            if data != -1:
                new_url = 'http://pic.yupoo.com' + data.get('data')[0].get('path')
                content = content.replace(i, new_url)
                print("正在替换图片。。。新地址为：%s"% new_url)
            else:
                error += 1
                print("出错啦：", msg)
    with open(base_path + file_name + '.md', 'w', encoding='utf8') as f:
        f.write(content)

    if error == 0:
        conn.query(Blog).filter(Blog.id == blog_obj.id).update({'replace_img': True})
        print(f'{file_name} 图片上传至Yupoo并替换完成！')


def get_result(future):
    ...


def replace_md_img(conn, base_path=base_path):
    # 建立线程池，加快进度
    with ThreadPoolExecutor(max_workers=4) as pool:
        blogs = conn.query(Blog).filter(Blog.replace_img == False).all()
        for blog in blogs:
            pool.submit(replace_img, conn, blog).add_done_callback(get_result)
    conn.commit()


def quit(conn):
    conn.close()
    exit('Bye~ ')


if __name__ == '__main__':
    conn = Connection()

    func_dict = {
        '1': ["数据库初始化", db_init],
        '2': ["添加源文件夹下所有md文件", add_all_md_to_db],
        '3': ["同步数据", sync_data_from_db],
        '4': ["替换md内图片", replace_md_img],
        '9': ["退出程序", quit],
    }
    while 1:
        print(f"嘟嘟博客管理平台：\n")
        for k, v in func_dict.items():
            print(f"\t{k} :   {v[0]}")
        choice = input("请选择功能的序号 >>>").strip()
        func = func_dict.get(choice)
        if func:
            func[1](conn)
        else:
            print("请输入正确的序号！ ")

